﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Text;
using DBBuilder.DBDataStructure;
using CommonLogging;
using AppsGenerator.Models;
using AppsGenerator.Utils;

namespace AppsGenerator.WebGenerators.WebViewGenerator
{
    /// <summary>
    /// The algorithm to generate the list view items for common table
    /// </summary>
    [Export(typeof(InsertViewItemByImageAndFCKAlgorithm))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class InsertViewItemByImageAndFCKAlgorithm : BaseInsertViewItemAlgorithm
    {
        /// <summary>
        /// The image attribute
        /// </summary>
        private string _imageAttr = string.Empty;

        /// <summary>
        /// The FCK attribute
        /// </summary>
        private string _fckAttr = string.Empty;

        /// <summary>
        /// The logger instance
        /// </summary>
        private readonly ILogger Logger = LoggerManager.GetLogger(typeof(InsertViewItemByImageAndFCKAlgorithm).Name);

        /// <summary>
        /// The default constructor
        /// </summary>
        public InsertViewItemByImageAndFCKAlgorithm()
        {
            this.XMLTemplate = "PartialInsertViewItemByImageAndFCK.xml";
            this.DeserializeTemplate();
        }

        /// <summary>
        /// Generate the contents of list view items
        /// </summary>
        /// <param name="tbl"></param>
        public override void GenerateContents(Table tbl)
        {
            this.Logger.InfoFormat("Generate InsertView[{0}] --> Start", tbl.Name);
            Console.WriteLine("Generate InsertView[{0}] --> Start", tbl.Name);

            try
            {
                var contents = new StringBuilder(BaseConsts.MAX_BYTES);
                tbl.IsTableWithImage(out this._imageAttr);
                tbl.IsTableWithFCK(out this._fckAttr);
                var htmlContents = this.ViewComponents.HtmlContent.Replace(BaseConsts.ConstTable, tbl.Name)
                    .Replace(BaseConsts.ConstGlobalNameSpace, WebConfiguration.Instance.NameSpace)
                    .Replace(BaseConsts.ConstImage, this._imageAttr)
                    .Replace(AbstractBaseConsts.ConstAttributeContent, this._fckAttr)
                    .Replace(AbstractBaseConsts.ConstScriptValidation, this.BuildScriptValidation(tbl))
                    .Replace(AbstractBaseConsts.ConstTableFields, this.BuildTableFields(tbl))
                    .Replace(AbstractBaseConsts.ConstForeignInputHidden, this.BuildForeignInputHidden(tbl));

                contents.AppendLine(htmlContents);

                // Init path
                this.DirPath = Path.Combine(this.GetAppPath(), "WebGenerator", "Views", tbl.Name + "Manager");
                this.InitializeDir(this.DirPath, false);
                // Save contents to a file
                this.SaveFile(contents.ToString().TrimStart(), "_PartialInsert.cshtml");
            }
            catch (Exception ex)
            {
                this.Logger.ErrorFormat("GenerateContents Error: {0}", ex.ToString());
                throw new Exception(ex.ToString());
            }

            this.Logger.InfoFormat("Generate InsertView[{0}] <-- End", tbl.Name);
            Console.WriteLine("Generate InsertView[{0}] <-- End", tbl.Name);
        }

        /// <summary>
        /// Build script for validation user inputs
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildScriptValidation(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var firstAtt = true;

            foreach (DBBuilder.DBDataStructure.Attribute attr in tbl.Attributes)
            {
                if (!attr.IsPrimaryKey && !attr.IsForeignKey &&
                    !attr.Name.Equals(this._imageAttr, StringComparison.OrdinalIgnoreCase))
                {
                    if (firstAtt)
                    {
                        firstAtt = false;
                        contents.AppendLine(string.Empty);
                    }

                    if (attr.Name.Equals(this._fckAttr, StringComparison.OrdinalIgnoreCase))
                    {
                        contents.Append(BaseConsts.TAB2).AppendLine(
                            string.Format("var {0} = CKEDITOR.instances.{1}.getData();", attr.Name.ToLower(), attr.Name));
                        contents.Append(BaseConsts.TAB2).AppendLine(string.Format("if ({0} == \"\") {{",
                                                                                  attr.Name.ToLower()));
                        contents.Append(BaseConsts.TAB3).AppendLine(
                            string.Format("$(\".red-left\").text('The input {0} is empty');", attr.Name));
                        contents.Append(BaseConsts.TAB3).AppendLine(
                            "$(\"#message-red\").fadeIn('fast').delay(@WebConfiguration.AlertTime).fadeOut('slow');");
                        contents.Append(BaseConsts.TAB3).AppendLine("return false;");
                        contents.Append(BaseConsts.TAB2).AppendLine("}");
                    }
                    else
                    {
                        contents.Append(BaseConsts.TAB2).AppendLine(
                            string.Format("var {0} = document.getElementsByName(\"{1}\").item(0);", attr.Name.ToLower(),
                                          attr.Name));
                        contents.Append(BaseConsts.TAB2).AppendLine(string.Format("if ({0}.value == \"\") {{",
                                                                                  attr.Name.ToLower()));
                        contents.Append(BaseConsts.TAB3).AppendLine(
                            string.Format("$(\".red-left\").text('The input {0} is empty');", attr.Name));
                        contents.Append(BaseConsts.TAB3).AppendLine(
                            "$(\"#message-red\").fadeIn('fast').delay(@WebConfiguration.AlertTime).fadeOut('slow');");
                        contents.Append(BaseConsts.TAB3).AppendLine("return false;");
                        contents.Append(BaseConsts.TAB2).AppendLine("}");
                    }
                }
            }

            return contents.ToString();
        }

        /// <summary>
        /// Generate the fields of table
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildTableFields(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var firstAtt = true;

            foreach (DBBuilder.DBDataStructure.Attribute attr in tbl.Attributes)
            {
                if (!attr.IsPrimaryKey && !attr.IsForeignKey &&
                    !attr.Name.Equals(this._imageAttr, StringComparison.OrdinalIgnoreCase))
                {
                    if (firstAtt)
                    {
                        firstAtt = false;
                        contents.AppendLine(string.Empty);
                    }

                    contents.Append(BaseConsts.TAB5).AppendLine("<tr>");
                    contents.Append(BaseConsts.TAB6).AppendLine("<th valign=\"top\" style=\"padding-top: 2px;\">");
                    contents.Append(BaseConsts.TAB7).AppendLine(string.Format("{0}:", attr.Name));
                    contents.Append(BaseConsts.TAB6).AppendLine("</th>");
                    contents.Append(BaseConsts.TAB6).AppendLine("<td>");

                    if (attr.Name.Equals(this._fckAttr, StringComparison.OrdinalIgnoreCase))
                    {
                        contents.Append(BaseConsts.TAB7).AppendLine(string.Format("@Html.TextArea(\"{0}\")",
                                                                                  attr.Name));
                    }
                    else
                    {
                        contents.Append(BaseConsts.TAB7).AppendLine(
                            string.Format("<input type=\"text\" name=\"{0}\" class=\"inp-form\" />", attr.Name));
                    }

                    contents.Append(BaseConsts.TAB6).AppendLine("</td>");
                    contents.Append(BaseConsts.TAB6).AppendLine("<td>");
                    contents.Append(BaseConsts.TAB6).AppendLine("</td>");
                    contents.Append(BaseConsts.TAB5).AppendLine("</tr>");
                }
            }

            return contents.ToString();
        }

        /// <summary>
        /// Generate the input hidden fields of table
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildForeignInputHidden(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var firstAtt = true;

            foreach (DBBuilder.DBDataStructure.Attribute attr in tbl.Attributes)
            {
                if (attr.IsForeignKey)
                {
                    if (firstAtt)
                    {
                        firstAtt = false;
                        contents.AppendLine(string.Empty);
                    }
                    var referTbl = tbl.DataBase.GetTable(attr.ReferTo);
                    if (referTbl.Name.Equals(WebConfiguration.Instance.Settings.UserTable, StringComparison.OrdinalIgnoreCase))
                    {
                        contents.Append(BaseConsts.TAB7).AppendLine(
                            string.Format(
                                "<input type=\"hidden\" name=\"{0}\" value=\"@Membership.GetUser( Page.User.Identity.Name).ProviderUserKey\" />",
                                attr.Name));
                    }
                    else
                    {
                        contents.Append(BaseConsts.TAB7).AppendLine(
                            string.Format("<input type=\"hidden\" name=\"{0}\" value=\"@Model.{1}[0].{2}\" />",
                                          attr.Name, attr.ReferTo.Pluralize(), referTbl.GetPrimaryKey().Name));
                    }
                }
            }

            return contents.ToString();
        }
    }
}
